#ifndef ___fat32_subtransaccion17_eliminar_directorio_completo

#define ___fat32_subtransaccion17_eliminar_directorio_completo 1

#include "f32_mto.c"

#include "f32_opAL.c"
#include "f32_opAM.c"
#include "f32_opAT.c"
#include "f32_opBC.c"
#include "f32_opBD.c"
#include "f32_opBE.c"
#include "f32_opBF.c"

struct fat32st17_directorio {
  unsigned long clusterInicial;
  unsigned long * cadena;
  unsigned short posicion;
  struct fat32st17_directorio * padre;
};

struct fat32st17_datos {
  unsigned long clusterInicioPadre;
  unsigned short numeroEntradaPadre;
  unsigned long * cadena;
  struct fat32st17_directorio * dirActual;
  unsigned long numeroBloque;
  char bloque[2048];
  unsigned long offsetBloque;
  unsigned long sectorEntradaPadre;
  unsigned int conexion;
  unsigned long clusterInicioElemento;
  fat32_lista_bloques_para_escribir * lbpe;
  unsigned char estadoEliminacion;
  char sectorEliminacion[512];
  unsigned long posicionEliminacion;
  unsigned long ultimoClusterOcupado;
  char datosElim[2048];
  unsigned short numeroEntradaInicial;
};

unsigned char fat32st_eliminar_directorio_completo(unsigned char, unsigned int, unsigned long, unsigned short, void **, unsigned char,
                                                                                                                               void *);
void fat32ast_insertar_nuevo_directorio_en_pila(struct fat32st17_directorio **);
void fat32ast_eliminar_directorio_actual_de_pila(struct fat32st17_directorio **);

unsigned char fat32st_eliminar_directorio_completo (unsigned char estado, unsigned int transaccion, unsigned long clusterInicioPadre,
                                                    unsigned short numeroEntrada, void ** datos, unsigned char estadoOp, void * datosOp) {
  struct fat32st17_datos * datosST = *datos;
  switch (estado) {
  case 0:
    datosST = malloc(sizeof(struct fat32st17_datos));
    *datos = datosST;
    datosST -> clusterInicioPadre = clusterInicioPadre;
    datosST -> numeroEntradaPadre = numeroEntrada;
    datosST -> dirActual = NULL;
    datosST -> numeroBloque = 0;
    datosST -> conexion = fat32_obtener_conexion_para_transaccion(transaccion);
    fat32_crear_operacion(transaccion, &fat32op_obtener_cadena_clusteres, &(datosST -> clusterInicioPadre),
                                                                    sizeof (datosST -> clusterInicioPadre));
    return 1;
  case 1:
    datosST -> cadena = datosOp;
    fat32_quitar_operacion(transaccion);
    unsigned long ccdp;
    for (ccdp = 0; (datosST -> cadena)[ccdp]; ccdp ++);
    fat32_crear_operacion(transaccion, &fat32op_obtener_cadena_sectores_desde_clusteres, &(datosST -> cadena),
                                                                       sizeof(unsigned long int) * (ccdp + 1));
    return 2;
  case 2:
    free(datosST -> cadena);
    datosST -> cadena = datosOp;
    fat32_quitar_operacion(transaccion);
    datosST -> numeroBloque = (datosST -> cadena)[(datosST -> numeroEntradaPadre) / 16];
    datosST -> offsetBloque = 512 * ((datosST -> numeroBloque) & 3);
    datosST -> numeroBloque &= ~3L;
    fat32opAM_solicitud_bloque dsp;
    dsp.conexion = datosST -> conexion;
    dsp.sector = datosST -> numeroBloque;
    dsp.buffer = datosST -> bloque;
    fat32_crear_operacion(transaccion, &fat32op_solicitar_bloque, &dsp, sizeof dsp);
    return 3;
  case 3:
    fat32_quitar_operacion(transaccion);
    char entradaPadre[32];
    memcpy(entradaPadre, (datosST -> bloque) + (datosST -> offsetBloque) + 32 * ((datosST -> numeroEntradaPadre) / 16), 32);
    unsigned long c1, c2, c3;
    c1 = fb_convertir_de_little_endian(entradaPadre + 20, 16);
    c2 = fb_convertir_de_little_endian(entradaPadre + 26, 16);
    c1 <<= 16;
    c3 = c1 + c2;
    fat32ast_insertar_nuevo_directorio_en_pila(&(datosST -> dirActual));
    (datosST -> dirActual) -> clusterInicial = c3;
    return 4;
  case 4:
    fat32_crear_operacion(transaccion, &fat32op_obtener_cadena_clusteres, &((datosST -> dirActual) -> clusterInicial),
                                                                    sizeof ((datosST -> dirActual) -> clusterInicial));
    return 5;
  case 5:
    (datosST -> dirActual) -> cadena = datosOp;
    fat32_quitar_operacion(transaccion);
    unsigned long ccda;
    for (ccda = 0; ((datosST -> dirActual) -> cadena)[ccda]; ccda ++);
    fat32_crear_operacion(transaccion, &fat32op_obtener_cadena_sectores_desde_clusteres, &((datosST -> dirActual) -> cadena),
                                                                                      sizeof(unsigned long int) * (ccda + 1));
    return 6;
  case 6:
    free((datosST -> dirActual) -> cadena);
    (datosST -> dirActual) -> cadena = datosOp;
    fat32_quitar_operacion(transaccion);
    return 7;
  case 7:
    46;
    unsigned long se;
    unsigned char pe;
    se = ((datosST -> dirActual) -> posicion) / 16;
    pe = ((datosST -> dirActual) -> posicion) % 16;
    se = ((datosST -> dirActual) -> cadena)[se];
    if (!se) return 15;
    unsigned long nbs = se & ~3L;
    datosST -> offsetBloque = 512 * (se & 3) + 32 * pe;
    if ((datosST -> numeroBloque) == nbs)
      return 9;
    datosST -> numeroBloque = nbs;
    struct fat32opAM_solicitud_bloque dbs;
    dbs.sector = nbs;
    dbs.conexion = datosST -> conexion;
    dbs.buffer = datosST -> bloque;
    fat32_crear_operacion(transaccion, &fat32op_solicitar_bloque, &dbs, sizeof dbs);
    return 8;
  case 8:
    fat32_quitar_operacion(transaccion);
    return 9;
  case 9:
    fat32_crear_operacion(transaccion, &fat32op_analizar_entrada_para_eliminacion, (datosST -> bloque) + (datosST -> offsetBloque), 32);
    return 10;
  case 10:
    if (datosOp) {
      datosST -> clusterInicialElemento = *((unsigned long *) datosOp);
      free(datosOp);
    }
    fat32_quitar_operacion(transaccion);
    switch (estadoOp) {
      case 4: return 14;
      case 3: return 15;
      case 2: return 13;
      case 1: return 11;
    }
  case 11:
    if (!(datosST -> clusterInicialElemento)) return 13;
    fat32_crear_operacion(transaccion, &fat32op_eliminar_cadena_clusteres, &(datosST -> clusterInicialElemento),
                                                                     sizeof (datosST -> clusterInicialElemento));
    return 12;
  case 12:
    fat32_quitar_operacion(transaccion);
    return 14;
  case 13:
    fat32ast_insertar_nuevo_directorio_en_pila(&(datosST -> dirActual));
    (datosST -> dirActual) -> clusterInicial = datosST -> clusterInicialElemento;
    return 4;
  case 14:
    (datosST -> dirActual) -> posicion ++;
    return 7;
  case 15:
    fat32ast_eliminar_directorio_actual_de_pila(&(datosST -> dirActual));
    if (datosST -> dirActual) return 14;
    return 16;
  case 16:
    if ((datosST -> numeroEntradaPadre) >= 32) {
      struct fat32opAM_solicitud_bloque ds1;
      ds1.conexion = datosST -> conexion;
      datosST -> numeroBloque = (datosST -> cadena)[(datosST -> numeroEntradaPadre) / 16 - 2];
      datosST -> offsetBloque = 512 * ((datosST -> numeroBloque) & 3);
      datosST -> numeroBloque &= ~3L;
      ds1.sector = datosST -> numeroBloque;
      ds1.buffer = datosST -> bloque;
      fat32_crear_operacion(transaccion, &fat32op_solicitar_bloque, &ds1, sizeof ds1);
      return 17;
    } else
      return 18;
  case 17:
    fat32_quitar_operacion(transaccion);
    unsigned short p1;
    for (p1 = 0, p1 < 512; p1 ++) (datosST -> datosElim)[p1] = (datosST -> bloque)[(datosST -> offsetBloque) + p1];
    return 19;
  case 18:
    46;
    unsigned short v1;
    for (v1 = 0; v1 < 512; v1 ++) (datosST -> datosElim)[v1] = 0;
    return 19;
  case 19:
    if ((datosST -> numeroEntradaPadre) >= 16) {
      struct fat32opAM_solicitud_bloque ds2;
      ds2.conexion = datosST -> conexion;
      datosST -> numeroBloque = (datosST -> cadena)[(datosST -> numeroEntradaPadre) / 16 - 1];
      datosST -> offsetBloque = 512 * ((datosST -> numeroBloque) & 3);
      datosST -> numeroBloque &= ~3L;
      ds2.sector = datosST -> numeroBloque;
      ds2.buffer = datosST -> bloque;
      fat32_crear_operacion(transaccion, &fat32op_solicitar_bloque, &ds2, sizeof ds2);
      return 20;
    } else
      return 21;
  case 20:
    fat32_quitar_operacion(transaccion);
    unsigned short p2;
    for (p2 = 0, p2 < 512; p2 ++) (datosST -> datosElim)[p2 + 512] = (datosST -> bloque)[(datosST -> offsetBloque) + p2];
    return 22;
  case 21:
    46;
    unsigned short v2;
    for (v2 = 512; v2 < 1024; v2 ++) (datosST -> datosElim)[v2] = 0;
    return 22;
  case 22:
    46;
    struct fat32opAM_solicitud_bloque ds3;
    ds3.conexion = datosST -> conexion;
    datosST -> numeroBloque = (datosST -> cadena)[(datosST -> numeroEntradaPadre) / 16];
    datosST -> offsetBloque = 512 * ((datosST -> numeroBloque) & 3);
    datosST -> numeroBloque &= ~3L;
    ds3.sector = datosST -> numeroBloque;
    ds3.buffer = datosST -> bloque;
    fat32_crear_operacion(transaccion, &fat32op_solicitar_bloque, &ds3, sizeof ds3);
    return 23;
  case 23:
    fat32_quitar_operacion(transaccion);
    unsigned short p3;
    for (p3 = 0; p3 < 512; p3 ++) (datosST -> datosElim)[p3 + 1024] = (datosST -> bloque)[(datosST -> offsetBloque) + p3];
    unsigned long sector4;
    sector4 = (datosST -> cadena)[(datosST -> numeroEntradaPadre) / 16 + 1];
    if (sector4) {
      struct fat32opAM_solicitud_bloque ds4;
      ds4.conexion = datosST -> conexion;
      datosST -> numeroBloque = (datosST -> cadena)[(datosST -> numeroEntradaPadre) / 16 + 1];
      datosST -> offsetBloque = 512 * ((datosST -> numeroBloque) & 3);
      datosST -> numeroBloque &= ~3L;
      ds4.sector = datosST -> numeroBloque;
      ds4.buffer = datosST -> bloque;
      fat32_crear_operacion(transaccion, &fat32op_solicitar_bloque, &ds4, sizeof ds4);
      return 24;
    } else
      return 25;
  case 24:
    fat32_quitar_operacion(transaccion);
    unsigned short p4;
    for (p4 = 0, p4 < 512; p4 ++) (datosST -> datosElim)[p4 + 1536] = (datosST -> bloque)[(datosST -> offsetBloque) + p4];
    return 26;
  case 25:
    46;
    unsigned short v4;
    for (v4 = 1536; v4 < 2048; v4 ++) (datosST -> datosElim)[v4] = 0;
    return 26;
  case 26:
    struct fat32opBD_datos_eliminacion dpe;
    dpe.numeroEntradaPadre = 32 + ((datosST -> numeroEntradaPadre) % 16);
    dpe.bufferDirectorio = datosST -> datosElim;
    fat32_crear_operacion(transaccion, &fat32op_determinar_primera_entrada_eliminacion, &dpe, sizeof dpe);
    return 27;
  case 27:
    fat32_quitar_operacion(transaccion);
    unsigned short diferencia = 32 + ((datosST -> numeroEntradaPadre) % 16);
    diferencia -= (estadoOp - 1);
    datosST -> numeroEntradaInicial = (datosST -> numeroEntradaPadre) - diferencia;
    return 28;
  case 28:
    datosST -> lbpe = malloc(sizeof(fat32_lista_bloques_para_escribir));
    fat32_operar_sobre_lista_bloques_para_escribir(FAT32_LBPE_CREAR, &(datosST -> lbpe), 0, 0, 0, NULL);
    unsigned short posicionEntradas;
    unsigned char numeroBorrado = 229;
    for (posicionEntradas = (datosST -> numeroEntradaInicial); posicionEntradas <= (datosST -> numeroEntradaPadre); posicionEntradas ++)
      fat32_operar_sobre_lista_bloques_para_escribir(FAT32_LBPE_ESCRIBIR, &(datosST -> lbpe), 
                                                     (datosST -> cadena)[posicionEntradas / 16] & ~3L,
                                                     32 * (posicionEntradas % 16) + 512 * ((datosST -> cadena)[posicionEntradas / 16] & 3),
                                                     1, &numeroBorrado);
    if ((datosST -> datosElim)[33 + ((datosST -> numeroEntradaPadre) % 16)])
      return 39;
    else
      return 29;
  case 29:
    datosST -> posicionEliminacion = ((datosST -> numeroEntradaInicial) - 1) / 16;
    unsigned short x = (datosST -> numeroEntradaPadre) & ~15;
    x -= (datosST -> numeroEntradaInicial) & ~15;
    x /= 16;
    datosST -> posicionEliminacion = (datosST -> numeroEntradaPadre) / 16 - x;
    x = 2 - x;
    memcpy(datosST -> sectorEliminacion, (datosST -> datosElim) + 512 * x, 512);
    if ((datosST -> numeroEntradaInicial) % 16)
      for (x = ((datosST -> numeroEntradaInicial) % 16) * 32; x < 512; x ++)
        (datosST -> sectorEliminacion)[x] = 0;
    return 30;
  case 30:
    fat32_crear_operacion(transaccion, &fat32op_ubicar_primera_entrada_ocupada_en_sector, datosST -> sectorEliminacion, 512);
    return 31;
  case 31:
    fat32_quitar_operacion(transaccion);
    datosST -> estadoEliminacion = estadoOp;
    if ((datosST -> estadoEliminacion) == 17) return 32;
    return 34;
  case 32:
    (datosST -> posicionEliminacion) --;
    datosST -> numeroBloque = (datosST -> cadena)[datosST -> posicionEliminacion];
    datosST -> offsetBloque = 512 * ((datosST -> numeroBloque) & 3);
    datosST -> numeroBloque &= ~3L;
    struct fat32opAM_solicitud_bloque ds;
    ds.conexion = datosST -> conexion;
    ds.sector = datosST -> numeroBloque;
    ds.buffer = datosST -> bloque;
    fat32_crear_operacion(transaccion, &fat32op_solicitar_bloque, &ds, sizeof ds);
    return 33;
  case 33:
    fat32_quitar_operacion(transaccion);
    memcpy(datosST -> sectorEliminacion, (datosST -> bloque) + (datosST -> offsetBloque), 512);
    return 30;
  case 34:
    46;
    unsigned long ps;
    char entradaNula[32];
    char sectorNulo[512];
    for (ps = 0; ps < 512; ps ++) {
      sectorNulo[ps] = 0;
      if (ps < 32) entradaNula[ps] = 0;
    }
    for (ps = (datosST -> estadoEliminacion); ps < 16; ps ++) {
      unsigned long bloqueE;
      unsigned short numeroE;
      bloqueE = (datosST -> cadena)[datosST -> posicionEliminacion];
      numeroE = 512 * (bloqueE & 3);
      bloqueE &= ~3L;
      fat32_operar_sobre_lista_bloques_para_escribir(FAT32_LBPE_ESCRIBIR, &(datosST -> lbpe), bloqueE, numeroE + 32 * ps, 32, entradaNula);
    }
    for (ps = (datosST -> posicionEliminacion) + 1; (datosST -> cadena)[ps]; ps ++) {
      unsigned long bloqueE;
      unsigned short numeroE;
      bloqueE = (datosST -> cadena)[ps];
      numeroE = 512 * (bloqueE & 3);
      bloqueE &= ~3L;
      fat32_operar_sobre_lista_bloques_para_escribir(FAT32_LBPE_ESCRIBIR, &(datosST -> lbpe), bloqueE, numeroE, 512, sectorNulo);
    }
    return 35;
  case 35:
    46;
    struct fat32_posicion_sector cs1, cs2;
    cs1 = fat32_obtener_posicion_sector((datosST -> cadena)[datosST -> posicionEliminacion], 0);
    unsigned long pcf;
    for (pcf = 0; (datosST -> cadena)[pcf + 1]; pcf ++);
    cs2 = fat32_obtener_posicion_sector((datosST -> cadena)[pcf], 0);
    if (cs1.cluster == cs2.cluster) return 39;
    datosST -> ultimoClusterOcupado = cs1.cluster;
    return 36;
  case 36:
    fat32_crear_operacion(transaccion, &fat32op_desvincular_clusteres, &(datosST -> ultimoClusterOcupado),
                                                                  sizeof (datosST -> ultimoClusterOcupado);
    return 37;
  case 37:
    fat32_quitar_operacion(transaccion);
    return 38;
  case 38:
    46;
    unsigned long posListaSectores;
    struct fat32_posicion_sector cs;
    for (posListaSectores = datosST -> posicionEliminacion; (datosST -> cadena)[posListaSectores]; posListaSectores ++) {
       cs = fat32_obtener_posicion_sector((datosST -> cadena)[posListaSectores], 0);
       if (cs.cluster != (datosST -> ultimoClusterOcupado)) break;
    }
    while ((datosST -> cadena)[posListaSectores]) {
      unsigned char x;
      fat32_operar_con_lista_bloques_para_escribir(FAT32_LBPE_BLOQUE_EXISTE_EN_LISTA, &(datosST -> lbpe),
                                                         (datosST -> cadena)[posListaSectores], 0, 0, &x);
      if (x) fat32_operar_con_lista_bloques_para_escribir(FAT32_LBPE_REMOVER_BLOQUE, &(datosST -> lbpe),
                                                      (datosST -> cadena)[posListaSectores], 0, 0, NULL);
      posListaSectores ++;
    }
    return 39;
  case 39:
    *datos = datosST -> lbpe;
    free(datosST -> cadena);
    while (datosST -> dirActual) fat32ast_eliminar_directorio_actual_de_pila(&(datosST -> dirActual));
    free(datosST);
    return 0;
  }
}

void fat32ast_insertar_nuevo_directorio_en_pila (struct fat32st17_directorio ** pila) {
  struct fat32st17_directorio * dir = malloc(sizeof(struct fat32st17_directorio));
  dir -> padre = *pila;
  dir -> clusterInicial = 0;
  dir -> posicion = 0;
  dir -> cadena = NULL;
  *pila = dir;
}

void fat32ast_eliminar_directorio_actual_de_pila (struct fat32st17_directorio ** pila) {
  struct fat32st17_directorio * dir = *pila;
  if (!dir) return;
  *pila = dir -> padre;
  if (dir -> cadena) free(dir -> cadena);
  free(dir);
}
                                                                                                                               
#endif